bootstrap.js ➔ getParent   C
last analyzed

Complexity

Conditions 10

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 7
dl 0
loc 12
rs 5.9999
c 0
b 0
f 0
cc 10

How to fix   Complexity   

Complexity

Complex classes like bootstrap.js ➔ getParent often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
/*!
2
 * Bootstrap v3.4.1 (https://getbootstrap.com/)
3
 * Copyright 2011-2019 Twitter, Inc.
4
 * Licensed under the MIT license
5
 */
6
7
if (typeof jQuery === 'undefined') {
8
  throw new Error('Bootstrap\'s JavaScript requires jQuery')
9
}
10
11
+function ($) {
12
  'use strict';
13
  var version = $.fn.jquery.split(' ')[0].split('.')
14
  if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1) || (version[0] > 3)) {
15
    throw new Error('Bootstrap\'s JavaScript requires jQuery version 1.9.1 or higher, but lower than version 4')
16
  }
17
}(jQuery);
18
19
/* ========================================================================
20
 * Bootstrap: transition.js v3.4.1
21
 * https://getbootstrap.com/docs/3.4/javascript/#transitions
22
 * ========================================================================
23
 * Copyright 2011-2019 Twitter, Inc.
24
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
25
 * ======================================================================== */
26
27
28
+function ($) {
29
  'use strict';
30
31
  // CSS TRANSITION SUPPORT (Shoutout: https://modernizr.com/)
32
  // ============================================================
33
34
  function transitionEnd() {
35
    var el = document.createElement('bootstrap')
36
37
    var transEndEventNames = {
38
      WebkitTransition : 'webkitTransitionEnd',
39
      MozTransition    : 'transitionend',
40
      OTransition      : 'oTransitionEnd otransitionend',
41
      transition       : 'transitionend'
42
    }
43
44
    for (var name in transEndEventNames) {
0 ignored issues
show
Complexity introduced by
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

When iterating over the keys of an object, this includes not only the keys of the object, but also keys contained in the prototype of that object. It is generally a best practice to check for these keys specifically:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
45
      if (el.style[name] !== undefined) {
46
        return { end: transEndEventNames[name] }
47
      }
48
    }
49
50
    return false // explicit for ie8 (  ._.)
51
  }
52
53
  // https://blog.alexmaccaw.com/css-transitions
54
  $.fn.emulateTransitionEnd = function (duration) {
55
    var called = false
56
    var $el = this
57
    $(this).one('bsTransitionEnd', function () { called = true })
58
    var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
59
    setTimeout(callback, duration)
60
    return this
61
  }
62
63
  $(function () {
64
    $.support.transition = transitionEnd()
65
66
    if (!$.support.transition) return
67
68
    $.event.special.bsTransitionEnd = {
69
      bindType: $.support.transition.end,
70
      delegateType: $.support.transition.end,
71
      handle: function (e) {
72
        if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments)
73
      }
74
    }
75
  })
76
77
}(jQuery);
78
79
/* ========================================================================
80
 * Bootstrap: alert.js v3.4.1
81
 * https://getbootstrap.com/docs/3.4/javascript/#alerts
82
 * ========================================================================
83
 * Copyright 2011-2019 Twitter, Inc.
84
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
85
 * ======================================================================== */
86
87
88
+function ($) {
89
  'use strict';
90
91
  // ALERT CLASS DEFINITION
92
  // ======================
93
94
  var dismiss = '[data-dismiss="alert"]'
95
  var Alert   = function (el) {
96
    $(el).on('click', dismiss, this.close)
97
  }
98
99
  Alert.VERSION = '3.4.1'
100
101
  Alert.TRANSITION_DURATION = 150
102
103
  Alert.prototype.close = function (e) {
104
    var $this    = $(this)
105
    var selector = $this.attr('data-target')
106
107
    if (!selector) {
108
      selector = $this.attr('href')
109
      selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
110
    }
111
112
    selector    = selector === '#' ? [] : selector
113
    var $parent = $(document).find(selector)
114
115
    if (e) e.preventDefault()
116
117
    if (!$parent.length) {
118
      $parent = $this.closest('.alert')
119
    }
120
121
    $parent.trigger(e = $.Event('close.bs.alert'))
122
123
    if (e.isDefaultPrevented()) return
124
125
    $parent.removeClass('in')
126
127
    function removeElement() {
128
      // detach from parent, fire event then clean up data
129
      $parent.detach().trigger('closed.bs.alert').remove()
130
    }
131
132
    $.support.transition && $parent.hasClass('fade') ?
133
      $parent
134
        .one('bsTransitionEnd', removeElement)
135
        .emulateTransitionEnd(Alert.TRANSITION_DURATION) :
136
      removeElement()
137
  }
138
139
140
  // ALERT PLUGIN DEFINITION
141
  // =======================
142
143
  function Plugin(option) {
144
    return this.each(function () {
145
      var $this = $(this)
146
      var data  = $this.data('bs.alert')
147
148
      if (!data) $this.data('bs.alert', (data = new Alert(this)))
149
      if (typeof option == 'string') data[option].call($this)
150
    })
151
  }
152
153
  var old = $.fn.alert
154
155
  $.fn.alert             = Plugin
156
  $.fn.alert.Constructor = Alert
157
158
159
  // ALERT NO CONFLICT
160
  // =================
161
162
  $.fn.alert.noConflict = function () {
163
    $.fn.alert = old
164
    return this
165
  }
166
167
168
  // ALERT DATA-API
169
  // ==============
170
171
  $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close)
172
173
}(jQuery);
174
175
/* ========================================================================
176
 * Bootstrap: button.js v3.4.1
177
 * https://getbootstrap.com/docs/3.4/javascript/#buttons
178
 * ========================================================================
179
 * Copyright 2011-2019 Twitter, Inc.
180
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
181
 * ======================================================================== */
182
183
184
+function ($) {
185
  'use strict';
186
187
  // BUTTON PUBLIC CLASS DEFINITION
188
  // ==============================
189
190
  var Button = function (element, options) {
191
    this.$element  = $(element)
192
    this.options   = $.extend({}, Button.DEFAULTS, options)
193
    this.isLoading = false
194
  }
195
196
  Button.VERSION  = '3.4.1'
197
198
  Button.DEFAULTS = {
199
    loadingText: 'loading...'
200
  }
201
202
  Button.prototype.setState = function (state) {
203
    var d    = 'disabled'
204
    var $el  = this.$element
205
    var val  = $el.is('input') ? 'val' : 'html'
206
    var data = $el.data()
207
208
    state += 'Text'
209
210
    if (data.resetText == null) $el.data('resetText', $el[val]())
211
212
    // push to event loop to allow forms to submit
213
    setTimeout($.proxy(function () {
214
      $el[val](data[state] == null ? this.options[state] : data[state])
215
216
      if (state == 'loadingText') {
217
        this.isLoading = true
218
        $el.addClass(d).attr(d, d).prop(d, true)
219
      } else if (this.isLoading) {
220
        this.isLoading = false
221
        $el.removeClass(d).removeAttr(d).prop(d, false)
222
      }
223
    }, this), 0)
224
  }
225
226
  Button.prototype.toggle = function () {
227
    var changed = true
228
    var $parent = this.$element.closest('[data-toggle="buttons"]')
229
230
    if ($parent.length) {
231
      var $input = this.$element.find('input')
232
      if ($input.prop('type') == 'radio') {
233
        if ($input.prop('checked')) changed = false
234
        $parent.find('.active').removeClass('active')
235
        this.$element.addClass('active')
236
      } else if ($input.prop('type') == 'checkbox') {
237
        if (($input.prop('checked')) !== this.$element.hasClass('active')) changed = false
238
        this.$element.toggleClass('active')
239
      }
240
      $input.prop('checked', this.$element.hasClass('active'))
241
      if (changed) $input.trigger('change')
242
    } else {
243
      this.$element.attr('aria-pressed', !this.$element.hasClass('active'))
244
      this.$element.toggleClass('active')
245
    }
246
  }
247
248
249
  // BUTTON PLUGIN DEFINITION
250
  // ========================
251
252
  function Plugin(option) {
253
    return this.each(function () {
254
      var $this   = $(this)
255
      var data    = $this.data('bs.button')
256
      var options = typeof option == 'object' && option
257
258
      if (!data) $this.data('bs.button', (data = new Button(this, options)))
259
260
      if (option == 'toggle') data.toggle()
261
      else if (option) data.setState(option)
262
    })
263
  }
264
265
  var old = $.fn.button
266
267
  $.fn.button             = Plugin
268
  $.fn.button.Constructor = Button
269
270
271
  // BUTTON NO CONFLICT
272
  // ==================
273
274
  $.fn.button.noConflict = function () {
275
    $.fn.button = old
276
    return this
277
  }
278
279
280
  // BUTTON DATA-API
281
  // ===============
282
283
  $(document)
284
    .on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) {
285
      var $btn = $(e.target).closest('.btn')
286
      Plugin.call($btn, 'toggle')
287
      if (!($(e.target).is('input[type="radio"], input[type="checkbox"]'))) {
288
        // Prevent double click on radios, and the double selections (so cancellation) on checkboxes
289
        e.preventDefault()
290
        // The target component still receive the focus
291
        if ($btn.is('input,button')) $btn.trigger('focus')
292
        else $btn.find('input:visible,button:visible').first().trigger('focus')
293
      }
294
    })
295
    .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) {
296
      $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type))
297
    })
298
299
}(jQuery);
300
301
/* ========================================================================
302
 * Bootstrap: carousel.js v3.4.1
303
 * https://getbootstrap.com/docs/3.4/javascript/#carousel
304
 * ========================================================================
305
 * Copyright 2011-2019 Twitter, Inc.
306
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
307
 * ======================================================================== */
308
309
310
+function ($) {
311
  'use strict';
312
313
  // CAROUSEL CLASS DEFINITION
314
  // =========================
315
316
  var Carousel = function (element, options) {
317
    this.$element    = $(element)
318
    this.$indicators = this.$element.find('.carousel-indicators')
319
    this.options     = options
320
    this.paused      = null
321
    this.sliding     = null
322
    this.interval    = null
323
    this.$active     = null
324
    this.$items      = null
325
326
    this.options.keyboard && this.$element.on('keydown.bs.carousel', $.proxy(this.keydown, this))
327
328
    this.options.pause == 'hover' && !('ontouchstart' in document.documentElement) && this.$element
329
      .on('mouseenter.bs.carousel', $.proxy(this.pause, this))
330
      .on('mouseleave.bs.carousel', $.proxy(this.cycle, this))
331
  }
332
333
  Carousel.VERSION  = '3.4.1'
334
335
  Carousel.TRANSITION_DURATION = 600
336
337
  Carousel.DEFAULTS = {
338
    interval: 5000,
339
    pause: 'hover',
340
    wrap: true,
341
    keyboard: true
342
  }
343
344
  Carousel.prototype.keydown = function (e) {
345
    if (/input|textarea/i.test(e.target.tagName)) return
346
    switch (e.which) {
347
      case 37: this.prev(); break
348
      case 39: this.next(); break
349
      default: return
350
    }
351
352
    e.preventDefault()
353
  }
354
355
  Carousel.prototype.cycle = function (e) {
356
    e || (this.paused = false)
357
358
    this.interval && clearInterval(this.interval)
359
360
    this.options.interval
361
      && !this.paused
362
      && (this.interval = setInterval($.proxy(this.next, this), this.options.interval))
363
364
    return this
365
  }
366
367
  Carousel.prototype.getItemIndex = function (item) {
368
    this.$items = item.parent().children('.item')
369
    return this.$items.index(item || this.$active)
370
  }
371
372
  Carousel.prototype.getItemForDirection = function (direction, active) {
373
    var activeIndex = this.getItemIndex(active)
374
    var willWrap = (direction == 'prev' && activeIndex === 0)
375
                || (direction == 'next' && activeIndex == (this.$items.length - 1))
376
    if (willWrap && !this.options.wrap) return active
377
    var delta = direction == 'prev' ? -1 : 1
378
    var itemIndex = (activeIndex + delta) % this.$items.length
379
    return this.$items.eq(itemIndex)
380
  }
381
382
  Carousel.prototype.to = function (pos) {
383
    var that        = this
384
    var activeIndex = this.getItemIndex(this.$active = this.$element.find('.item.active'))
385
386
    if (pos > (this.$items.length - 1) || pos < 0) return
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
387
388
    if (this.sliding)       return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) // yes, "slid"
389
    if (activeIndex == pos) return this.pause().cycle()
390
391
    return this.slide(pos > activeIndex ? 'next' : 'prev', this.$items.eq(pos))
392
  }
393
394
  Carousel.prototype.pause = function (e) {
395
    e || (this.paused = true)
396
397
    if (this.$element.find('.next, .prev').length && $.support.transition) {
398
      this.$element.trigger($.support.transition.end)
399
      this.cycle(true)
400
    }
401
402
    this.interval = clearInterval(this.interval)
403
404
    return this
405
  }
406
407
  Carousel.prototype.next = function () {
408
    if (this.sliding) return
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
409
    return this.slide('next')
410
  }
411
412
  Carousel.prototype.prev = function () {
413
    if (this.sliding) return
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
414
    return this.slide('prev')
415
  }
416
417
  Carousel.prototype.slide = function (type, next) {
418
    var $active   = this.$element.find('.item.active')
419
    var $next     = next || this.getItemForDirection(type, $active)
420
    var isCycling = this.interval
421
    var direction = type == 'next' ? 'left' : 'right'
422
    var that      = this
423
424
    if ($next.hasClass('active')) return (this.sliding = false)
425
426
    var relatedTarget = $next[0]
427
    var slideEvent = $.Event('slide.bs.carousel', {
428
      relatedTarget: relatedTarget,
429
      direction: direction
430
    })
431
    this.$element.trigger(slideEvent)
432
    if (slideEvent.isDefaultPrevented()) return
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
433
434
    this.sliding = true
435
436
    isCycling && this.pause()
437
438
    if (this.$indicators.length) {
439
      this.$indicators.find('.active').removeClass('active')
440
      var $nextIndicator = $(this.$indicators.children()[this.getItemIndex($next)])
441
      $nextIndicator && $nextIndicator.addClass('active')
442
    }
443
444
    var slidEvent = $.Event('slid.bs.carousel', { relatedTarget: relatedTarget, direction: direction }) // yes, "slid"
445
    if ($.support.transition && this.$element.hasClass('slide')) {
446
      $next.addClass(type)
447
      if (typeof $next === 'object' && $next.length) {
448
        $next[0].offsetWidth // force reflow
0 ignored issues
show
introduced by
The result of the property access to $next.0.offsetWidth is not used.
Loading history...
449
      }
450
      $active.addClass(direction)
451
      $next.addClass(direction)
452
      $active
453
        .one('bsTransitionEnd', function () {
454
          $next.removeClass([type, direction].join(' ')).addClass('active')
455
          $active.removeClass(['active', direction].join(' '))
456
          that.sliding = false
457
          setTimeout(function () {
458
            that.$element.trigger(slidEvent)
459
          }, 0)
460
        })
461
        .emulateTransitionEnd(Carousel.TRANSITION_DURATION)
462
    } else {
463
      $active.removeClass('active')
464
      $next.addClass('active')
465
      this.sliding = false
466
      this.$element.trigger(slidEvent)
467
    }
468
469
    isCycling && this.cycle()
470
471
    return this
472
  }
473
474
475
  // CAROUSEL PLUGIN DEFINITION
476
  // ==========================
477
478
  function Plugin(option) {
479
    return this.each(function () {
480
      var $this   = $(this)
481
      var data    = $this.data('bs.carousel')
482
      var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option)
483
      var action  = typeof option == 'string' ? option : options.slide
484
485
      if (!data) $this.data('bs.carousel', (data = new Carousel(this, options)))
486
      if (typeof option == 'number') data.to(option)
487
      else if (action) data[action]()
488
      else if (options.interval) data.pause().cycle()
489
    })
490
  }
491
492
  var old = $.fn.carousel
493
494
  $.fn.carousel             = Plugin
495
  $.fn.carousel.Constructor = Carousel
496
497
498
  // CAROUSEL NO CONFLICT
499
  // ====================
500
501
  $.fn.carousel.noConflict = function () {
502
    $.fn.carousel = old
503
    return this
504
  }
505
506
507
  // CAROUSEL DATA-API
508
  // =================
509
510
  var clickHandler = function (e) {
511
    var $this   = $(this)
512
    var href    = $this.attr('href')
513
    if (href) {
514
      href = href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7
515
    }
516
517
    var target  = $this.attr('data-target') || href
518
    var $target = $(document).find(target)
519
520
    if (!$target.hasClass('carousel')) return
521
522
    var options = $.extend({}, $target.data(), $this.data())
523
    var slideIndex = $this.attr('data-slide-to')
524
    if (slideIndex) options.interval = false
525
526
    Plugin.call($target, options)
527
528
    if (slideIndex) {
529
      $target.data('bs.carousel').to(slideIndex)
530
    }
531
532
    e.preventDefault()
533
  }
534
535
  $(document)
536
    .on('click.bs.carousel.data-api', '[data-slide]', clickHandler)
537
    .on('click.bs.carousel.data-api', '[data-slide-to]', clickHandler)
538
539
  $(window).on('load', function () {
540
    $('[data-ride="carousel"]').each(function () {
541
      var $carousel = $(this)
542
      Plugin.call($carousel, $carousel.data())
543
    })
544
  })
545
546
}(jQuery);
547
548
/* ========================================================================
549
 * Bootstrap: collapse.js v3.4.1
550
 * https://getbootstrap.com/docs/3.4/javascript/#collapse
551
 * ========================================================================
552
 * Copyright 2011-2019 Twitter, Inc.
553
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
554
 * ======================================================================== */
555
556
/* jshint latedef: false */
557
558
+function ($) {
559
  'use strict';
560
561
  // COLLAPSE PUBLIC CLASS DEFINITION
562
  // ================================
563
564
  var Collapse = function (element, options) {
565
    this.$element      = $(element)
566
    this.options       = $.extend({}, Collapse.DEFAULTS, options)
567
    this.$trigger      = $('[data-toggle="collapse"][href="#' + element.id + '"],' +
568
                           '[data-toggle="collapse"][data-target="#' + element.id + '"]')
569
    this.transitioning = null
570
571
    if (this.options.parent) {
572
      this.$parent = this.getParent()
573
    } else {
574
      this.addAriaAndCollapsedClass(this.$element, this.$trigger)
575
    }
576
577
    if (this.options.toggle) this.toggle()
578
  }
579
580
  Collapse.VERSION  = '3.4.1'
581
582
  Collapse.TRANSITION_DURATION = 350
583
584
  Collapse.DEFAULTS = {
585
    toggle: true
586
  }
587
588
  Collapse.prototype.dimension = function () {
589
    var hasWidth = this.$element.hasClass('width')
590
    return hasWidth ? 'width' : 'height'
591
  }
592
593
  Collapse.prototype.show = function () {
594
    if (this.transitioning || this.$element.hasClass('in')) return
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
595
596
    var activesData
597
    var actives = this.$parent && this.$parent.children('.panel').children('.in, .collapsing')
598
599
    if (actives && actives.length) {
600
      activesData = actives.data('bs.collapse')
601
      if (activesData && activesData.transitioning) return
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
602
    }
603
604
    var startEvent = $.Event('show.bs.collapse')
605
    this.$element.trigger(startEvent)
606
    if (startEvent.isDefaultPrevented()) return
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
607
608
    if (actives && actives.length) {
609
      Plugin.call(actives, 'hide')
610
      activesData || actives.data('bs.collapse', null)
611
    }
612
613
    var dimension = this.dimension()
614
615
    this.$element
616
      .removeClass('collapse')
617
      .addClass('collapsing')[dimension](0)
618
      .attr('aria-expanded', true)
619
620
    this.$trigger
621
      .removeClass('collapsed')
622
      .attr('aria-expanded', true)
623
624
    this.transitioning = 1
625
626
    var complete = function () {
627
      this.$element
628
        .removeClass('collapsing')
629
        .addClass('collapse in')[dimension]('')
630
      this.transitioning = 0
631
      this.$element
632
        .trigger('shown.bs.collapse')
633
    }
634
635
    if (!$.support.transition) return complete.call(this)
636
637
    var scrollSize = $.camelCase(['scroll', dimension].join('-'))
638
639
    this.$element
640
      .one('bsTransitionEnd', $.proxy(complete, this))
641
      .emulateTransitionEnd(Collapse.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize])
642
  }
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
643
644
  Collapse.prototype.hide = function () {
645
    if (this.transitioning || !this.$element.hasClass('in')) return
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
646
647
    var startEvent = $.Event('hide.bs.collapse')
648
    this.$element.trigger(startEvent)
649
    if (startEvent.isDefaultPrevented()) return
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
650
651
    var dimension = this.dimension()
652
653
    this.$element[dimension](this.$element[dimension]())[0].offsetHeight
0 ignored issues
show
introduced by
The result of the property access to this.$element.dimension(...nsion()).0.offsetHeight is not used.
Loading history...
654
655
    this.$element
656
      .addClass('collapsing')
657
      .removeClass('collapse in')
658
      .attr('aria-expanded', false)
659
660
    this.$trigger
661
      .addClass('collapsed')
662
      .attr('aria-expanded', false)
663
664
    this.transitioning = 1
665
666
    var complete = function () {
667
      this.transitioning = 0
668
      this.$element
669
        .removeClass('collapsing')
670
        .addClass('collapse')
671
        .trigger('hidden.bs.collapse')
672
    }
673
674
    if (!$.support.transition) return complete.call(this)
675
676
    this.$element
677
      [dimension](0)
678
      .one('bsTransitionEnd', $.proxy(complete, this))
679
      .emulateTransitionEnd(Collapse.TRANSITION_DURATION)
680
  }
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
681
682
  Collapse.prototype.toggle = function () {
683
    this[this.$element.hasClass('in') ? 'hide' : 'show']()
684
  }
685
686
  Collapse.prototype.getParent = function () {
687
    return $(document).find(this.options.parent)
688
      .find('[data-toggle="collapse"][data-parent="' + this.options.parent + '"]')
689
      .each($.proxy(function (i, element) {
690
        var $element = $(element)
691
        this.addAriaAndCollapsedClass(getTargetFromTrigger($element), $element)
692
      }, this))
693
      .end()
694
  }
695
696
  Collapse.prototype.addAriaAndCollapsedClass = function ($element, $trigger) {
697
    var isOpen = $element.hasClass('in')
698
699
    $element.attr('aria-expanded', isOpen)
700
    $trigger
701
      .toggleClass('collapsed', !isOpen)
702
      .attr('aria-expanded', isOpen)
703
  }
704
705
  function getTargetFromTrigger($trigger) {
706
    var href
707
    var target = $trigger.attr('data-target')
708
      || (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7
709
710
    return $(document).find(target)
711
  }
712
713
714
  // COLLAPSE PLUGIN DEFINITION
715
  // ==========================
716
717
  function Plugin(option) {
718
    return this.each(function () {
719
      var $this   = $(this)
720
      var data    = $this.data('bs.collapse')
721
      var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)
722
723
      if (!data && options.toggle && /show|hide/.test(option)) options.toggle = false
724
      if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
725
      if (typeof option == 'string') data[option]()
726
    })
727
  }
728
729
  var old = $.fn.collapse
730
731
  $.fn.collapse             = Plugin
732
  $.fn.collapse.Constructor = Collapse
733
734
735
  // COLLAPSE NO CONFLICT
736
  // ====================
737
738
  $.fn.collapse.noConflict = function () {
739
    $.fn.collapse = old
740
    return this
741
  }
742
743
744
  // COLLAPSE DATA-API
745
  // =================
746
747
  $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) {
748
    var $this   = $(this)
749
750
    if (!$this.attr('data-target')) e.preventDefault()
751
752
    var $target = getTargetFromTrigger($this)
753
    var data    = $target.data('bs.collapse')
754
    var option  = data ? 'toggle' : $this.data()
755
756
    Plugin.call($target, option)
757
  })
758
759
}(jQuery);
760
761
/* ========================================================================
762
 * Bootstrap: dropdown.js v3.4.1
763
 * https://getbootstrap.com/docs/3.4/javascript/#dropdowns
764
 * ========================================================================
765
 * Copyright 2011-2019 Twitter, Inc.
766
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
767
 * ======================================================================== */
768
769
770
+function ($) {
771
  'use strict';
772
773
  // DROPDOWN CLASS DEFINITION
774
  // =========================
775
776
  var backdrop = '.dropdown-backdrop'
777
  var toggle   = '[data-toggle="dropdown"]'
778
  var Dropdown = function (element) {
779
    $(element).on('click.bs.dropdown', this.toggle)
780
  }
781
782
  Dropdown.VERSION = '3.4.1'
783
784
  function getParent($this) {
785
    var selector = $this.attr('data-target')
786
787
    if (!selector) {
788
      selector = $this.attr('href')
789
      selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
790
    }
791
792
    var $parent = selector !== '#' ? $(document).find(selector) : null
793
794
    return $parent && $parent.length ? $parent : $this.parent()
795
  }
796
797
  function clearMenus(e) {
798
    if (e && e.which === 3) return
799
    $(backdrop).remove()
800
    $(toggle).each(function () {
801
      var $this         = $(this)
802
      var $parent       = getParent($this)
803
      var relatedTarget = { relatedTarget: this }
804
805
      if (!$parent.hasClass('open')) return
806
807
      if (e && e.type == 'click' && /input|textarea/i.test(e.target.tagName) && $.contains($parent[0], e.target)) return
808
809
      $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
810
811
      if (e.isDefaultPrevented()) return
812
813
      $this.attr('aria-expanded', 'false')
814
      $parent.removeClass('open').trigger($.Event('hidden.bs.dropdown', relatedTarget))
815
    })
816
  }
817
818
  Dropdown.prototype.toggle = function (e) {
819
    var $this = $(this)
820
821
    if ($this.is('.disabled, :disabled')) return
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
822
823
    var $parent  = getParent($this)
824
    var isActive = $parent.hasClass('open')
825
826
    clearMenus()
827
828
    if (!isActive) {
829
      if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
830
        // if mobile we use a backdrop because click events don't delegate
831
        $(document.createElement('div'))
832
          .addClass('dropdown-backdrop')
833
          .insertAfter($(this))
834
          .on('click', clearMenus)
835
      }
836
837
      var relatedTarget = { relatedTarget: this }
838
      $parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))
839
840
      if (e.isDefaultPrevented()) return
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
841
842
      $this
843
        .trigger('focus')
844
        .attr('aria-expanded', 'true')
845
846
      $parent
847
        .toggleClass('open')
848
        .trigger($.Event('shown.bs.dropdown', relatedTarget))
849
    }
850
851
    return false
852
  }
853
854
  Dropdown.prototype.keydown = function (e) {
855
    if (!/(38|40|27|32)/.test(e.which) || /input|textarea/i.test(e.target.tagName)) return
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
856
857
    var $this = $(this)
858
859
    e.preventDefault()
860
    e.stopPropagation()
861
862
    if ($this.is('.disabled, :disabled')) return
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
863
864
    var $parent  = getParent($this)
865
    var isActive = $parent.hasClass('open')
866
867
    if (!isActive && e.which != 27 || isActive && e.which == 27) {
868
      if (e.which == 27) $parent.find(toggle).trigger('focus')
869
      return $this.trigger('click')
870
    }
871
872
    var desc = ' li:not(.disabled):visible a'
873
    var $items = $parent.find('.dropdown-menu' + desc)
874
875
    if (!$items.length) return
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
876
877
    var index = $items.index(e.target)
878
879
    if (e.which == 38 && index > 0)                 index--         // up
880
    if (e.which == 40 && index < $items.length - 1) index++         // down
881
    if (!~index)                                    index = 0
882
883
    $items.eq(index).trigger('focus')
884
  }
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
885
886
887
  // DROPDOWN PLUGIN DEFINITION
888
  // ==========================
889
890
  function Plugin(option) {
891
    return this.each(function () {
892
      var $this = $(this)
893
      var data  = $this.data('bs.dropdown')
894
895
      if (!data) $this.data('bs.dropdown', (data = new Dropdown(this)))
896
      if (typeof option == 'string') data[option].call($this)
897
    })
898
  }
899
900
  var old = $.fn.dropdown
901
902
  $.fn.dropdown             = Plugin
903
  $.fn.dropdown.Constructor = Dropdown
904
905
906
  // DROPDOWN NO CONFLICT
907
  // ====================
908
909
  $.fn.dropdown.noConflict = function () {
910
    $.fn.dropdown = old
911
    return this
912
  }
913
914
915
  // APPLY TO STANDARD DROPDOWN ELEMENTS
916
  // ===================================
917
918
  $(document)
919
    .on('click.bs.dropdown.data-api', clearMenus)
920
    .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
921
    .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)
922
    .on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown)
923
    .on('keydown.bs.dropdown.data-api', '.dropdown-menu', Dropdown.prototype.keydown)
924
925
}(jQuery);
926
927
/* ========================================================================
928
 * Bootstrap: modal.js v3.4.1
929
 * https://getbootstrap.com/docs/3.4/javascript/#modals
930
 * ========================================================================
931
 * Copyright 2011-2019 Twitter, Inc.
932
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
933
 * ======================================================================== */
934
935
936
+function ($) {
937
  'use strict';
938
939
  // MODAL CLASS DEFINITION
940
  // ======================
941
942
  var Modal = function (element, options) {
943
    this.options = options
944
    this.$body = $(document.body)
945
    this.$element = $(element)
946
    this.$dialog = this.$element.find('.modal-dialog')
947
    this.$backdrop = null
948
    this.isShown = null
949
    this.originalBodyPad = null
950
    this.scrollbarWidth = 0
951
    this.ignoreBackdropClick = false
952
    this.fixedContent = '.navbar-fixed-top, .navbar-fixed-bottom'
953
954
    if (this.options.remote) {
955
      this.$element
956
        .find('.modal-content')
957
        .load(this.options.remote, $.proxy(function () {
958
          this.$element.trigger('loaded.bs.modal')
959
        }, this))
960
    }
961
  }
962
963
  Modal.VERSION = '3.4.1'
964
965
  Modal.TRANSITION_DURATION = 300
966
  Modal.BACKDROP_TRANSITION_DURATION = 150
967
968
  Modal.DEFAULTS = {
969
    backdrop: true,
970
    keyboard: true,
971
    show: true
972
  }
973
974
  Modal.prototype.toggle = function (_relatedTarget) {
975
    return this.isShown ? this.hide() : this.show(_relatedTarget)
976
  }
977
978
  Modal.prototype.show = function (_relatedTarget) {
979
    var that = this
980
    var e = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })
981
982
    this.$element.trigger(e)
983
984
    if (this.isShown || e.isDefaultPrevented()) return
985
986
    this.isShown = true
987
988
    this.checkScrollbar()
989
    this.setScrollbar()
990
    this.$body.addClass('modal-open')
991
992
    this.escape()
993
    this.resize()
994
995
    this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this))
996
997
    this.$dialog.on('mousedown.dismiss.bs.modal', function () {
998
      that.$element.one('mouseup.dismiss.bs.modal', function (e) {
999
        if ($(e.target).is(that.$element)) that.ignoreBackdropClick = true
1000
      })
1001
    })
1002
1003
    this.backdrop(function () {
1004
      var transition = $.support.transition && that.$element.hasClass('fade')
1005
1006
      if (!that.$element.parent().length) {
1007
        that.$element.appendTo(that.$body) // don't move modals dom position
1008
      }
1009
1010
      that.$element
1011
        .show()
1012
        .scrollTop(0)
1013
1014
      that.adjustDialog()
1015
1016
      if (transition) {
1017
        that.$element[0].offsetWidth // force reflow
0 ignored issues
show
introduced by
The result of the property access to that.$element.0.offsetWidth is not used.
Loading history...
1018
      }
1019
1020
      that.$element.addClass('in')
1021
1022
      that.enforceFocus()
1023
1024
      var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })
1025
1026
      transition ?
1027
        that.$dialog // wait for modal to slide in
1028
          .one('bsTransitionEnd', function () {
1029
            that.$element.trigger('focus').trigger(e)
1030
          })
1031
          .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
1032
        that.$element.trigger('focus').trigger(e)
1033
    })
1034
  }
1035
1036
  Modal.prototype.hide = function (e) {
1037
    if (e) e.preventDefault()
1038
1039
    e = $.Event('hide.bs.modal')
1040
1041
    this.$element.trigger(e)
1042
1043
    if (!this.isShown || e.isDefaultPrevented()) return
1044
1045
    this.isShown = false
1046
1047
    this.escape()
1048
    this.resize()
1049
1050
    $(document).off('focusin.bs.modal')
1051
1052
    this.$element
1053
      .removeClass('in')
1054
      .off('click.dismiss.bs.modal')
1055
      .off('mouseup.dismiss.bs.modal')
1056
1057
    this.$dialog.off('mousedown.dismiss.bs.modal')
1058
1059
    $.support.transition && this.$element.hasClass('fade') ?
1060
      this.$element
1061
        .one('bsTransitionEnd', $.proxy(this.hideModal, this))
1062
        .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
1063
      this.hideModal()
1064
  }
1065
1066
  Modal.prototype.enforceFocus = function () {
1067
    $(document)
1068
      .off('focusin.bs.modal') // guard against infinite focus loop
1069
      .on('focusin.bs.modal', $.proxy(function (e) {
1070
        if (document !== e.target &&
1071
          this.$element[0] !== e.target &&
1072
          !this.$element.has(e.target).length) {
1073
          this.$element.trigger('focus')
1074
        }
1075
      }, this))
1076
  }
1077
1078
  Modal.prototype.escape = function () {
1079
    if (this.isShown && this.options.keyboard) {
1080
      this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) {
1081
        e.which == 27 && this.hide()
1082
      }, this))
1083
    } else if (!this.isShown) {
1084
      this.$element.off('keydown.dismiss.bs.modal')
1085
    }
1086
  }
1087
1088
  Modal.prototype.resize = function () {
1089
    if (this.isShown) {
1090
      $(window).on('resize.bs.modal', $.proxy(this.handleUpdate, this))
1091
    } else {
1092
      $(window).off('resize.bs.modal')
1093
    }
1094
  }
1095
1096
  Modal.prototype.hideModal = function () {
1097
    var that = this
1098
    this.$element.hide()
1099
    this.backdrop(function () {
1100
      that.$body.removeClass('modal-open')
1101
      that.resetAdjustments()
1102
      that.resetScrollbar()
1103
      that.$element.trigger('hidden.bs.modal')
1104
    })
1105
  }
1106
1107
  Modal.prototype.removeBackdrop = function () {
1108
    this.$backdrop && this.$backdrop.remove()
1109
    this.$backdrop = null
1110
  }
1111
1112
  Modal.prototype.backdrop = function (callback) {
1113
    var that = this
1114
    var animate = this.$element.hasClass('fade') ? 'fade' : ''
1115
1116
    if (this.isShown && this.options.backdrop) {
1117
      var doAnimate = $.support.transition && animate
1118
1119
      this.$backdrop = $(document.createElement('div'))
1120
        .addClass('modal-backdrop ' + animate)
1121
        .appendTo(this.$body)
1122
1123
      this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) {
1124
        if (this.ignoreBackdropClick) {
1125
          this.ignoreBackdropClick = false
1126
          return
1127
        }
1128
        if (e.target !== e.currentTarget) return
1129
        this.options.backdrop == 'static'
1130
          ? this.$element[0].focus()
1131
          : this.hide()
1132
      }, this))
1133
1134
      if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
1135
1136
      this.$backdrop.addClass('in')
1137
1138
      if (!callback) return
1139
1140
      doAnimate ?
1141
        this.$backdrop
1142
          .one('bsTransitionEnd', callback)
1143
          .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
1144
        callback()
1145
1146
    } else if (!this.isShown && this.$backdrop) {
1147
      this.$backdrop.removeClass('in')
1148
1149
      var callbackRemove = function () {
1150
        that.removeBackdrop()
1151
        callback && callback()
1152
      }
1153
      $.support.transition && this.$element.hasClass('fade') ?
1154
        this.$backdrop
1155
          .one('bsTransitionEnd', callbackRemove)
1156
          .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
1157
        callbackRemove()
1158
1159
    } else if (callback) {
1160
      callback()
1161
    }
1162
  }
1163
1164
  // these following methods are used to handle overflowing modals
1165
1166
  Modal.prototype.handleUpdate = function () {
1167
    this.adjustDialog()
1168
  }
1169
1170
  Modal.prototype.adjustDialog = function () {
1171
    var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight
1172
1173
    this.$element.css({
1174
      paddingLeft: !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '',
1175
      paddingRight: this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : ''
1176
    })
1177
  }
1178
1179
  Modal.prototype.resetAdjustments = function () {
1180
    this.$element.css({
1181
      paddingLeft: '',
1182
      paddingRight: ''
1183
    })
1184
  }
1185
1186
  Modal.prototype.checkScrollbar = function () {
1187
    var fullWindowWidth = window.innerWidth
1188
    if (!fullWindowWidth) { // workaround for missing window.innerWidth in IE8
1189
      var documentElementRect = document.documentElement.getBoundingClientRect()
1190
      fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left)
1191
    }
1192
    this.bodyIsOverflowing = document.body.clientWidth < fullWindowWidth
1193
    this.scrollbarWidth = this.measureScrollbar()
1194
  }
1195
1196
  Modal.prototype.setScrollbar = function () {
1197
    var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10)
1198
    this.originalBodyPad = document.body.style.paddingRight || ''
1199
    var scrollbarWidth = this.scrollbarWidth
1200
    if (this.bodyIsOverflowing) {
1201
      this.$body.css('padding-right', bodyPad + scrollbarWidth)
1202
      $(this.fixedContent).each(function (index, element) {
1203
        var actualPadding = element.style.paddingRight
1204
        var calculatedPadding = $(element).css('padding-right')
1205
        $(element)
1206
          .data('padding-right', actualPadding)
1207
          .css('padding-right', parseFloat(calculatedPadding) + scrollbarWidth + 'px')
1208
      })
1209
    }
1210
  }
1211
1212
  Modal.prototype.resetScrollbar = function () {
1213
    this.$body.css('padding-right', this.originalBodyPad)
1214
    $(this.fixedContent).each(function (index, element) {
1215
      var padding = $(element).data('padding-right')
1216
      $(element).removeData('padding-right')
1217
      element.style.paddingRight = padding ? padding : ''
1218
    })
1219
  }
1220
1221
  Modal.prototype.measureScrollbar = function () { // thx walsh
1222
    var scrollDiv = document.createElement('div')
1223
    scrollDiv.className = 'modal-scrollbar-measure'
1224
    this.$body.append(scrollDiv)
1225
    var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth
1226
    this.$body[0].removeChild(scrollDiv)
1227
    return scrollbarWidth
1228
  }
1229
1230
1231
  // MODAL PLUGIN DEFINITION
1232
  // =======================
1233
1234
  function Plugin(option, _relatedTarget) {
1235
    return this.each(function () {
1236
      var $this = $(this)
1237
      var data = $this.data('bs.modal')
1238
      var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)
1239
1240
      if (!data) $this.data('bs.modal', (data = new Modal(this, options)))
1241
      if (typeof option == 'string') data[option](_relatedTarget)
1242
      else if (options.show) data.show(_relatedTarget)
1243
    })
1244
  }
1245
1246
  var old = $.fn.modal
1247
1248
  $.fn.modal = Plugin
1249
  $.fn.modal.Constructor = Modal
1250
1251
1252
  // MODAL NO CONFLICT
1253
  // =================
1254
1255
  $.fn.modal.noConflict = function () {
1256
    $.fn.modal = old
1257
    return this
1258
  }
1259
1260
1261
  // MODAL DATA-API
1262
  // ==============
1263
1264
  $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) {
1265
    var $this = $(this)
1266
    var href = $this.attr('href')
1267
    var target = $this.attr('data-target') ||
1268
      (href && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7
1269
1270
    var $target = $(document).find(target)
1271
    var option = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())
1272
1273
    if ($this.is('a')) e.preventDefault()
1274
1275
    $target.one('show.bs.modal', function (showEvent) {
1276
      if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown
1277
      $target.one('hidden.bs.modal', function () {
1278
        $this.is(':visible') && $this.trigger('focus')
1279
      })
1280
    })
1281
    Plugin.call($target, option, this)
1282
  })
1283
1284
}(jQuery);
1285
1286
/* ========================================================================
1287
 * Bootstrap: tooltip.js v3.4.1
1288
 * https://getbootstrap.com/docs/3.4/javascript/#tooltip
1289
 * Inspired by the original jQuery.tipsy by Jason Frame
1290
 * ========================================================================
1291
 * Copyright 2011-2019 Twitter, Inc.
1292
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
1293
 * ======================================================================== */
1294
1295
+function ($) {
1296
  'use strict';
1297
1298
  var DISALLOWED_ATTRIBUTES = ['sanitize', 'whiteList', 'sanitizeFn']
1299
1300
  var uriAttrs = [
1301
    'background',
1302
    'cite',
1303
    'href',
1304
    'itemtype',
1305
    'longdesc',
1306
    'poster',
1307
    'src',
1308
    'xlink:href'
1309
  ]
1310
1311
  var ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i
1312
1313
  var DefaultWhitelist = {
1314
    // Global attributes allowed on any supplied element below.
1315
    '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],
1316
    a: ['target', 'href', 'title', 'rel'],
1317
    area: [],
1318
    b: [],
1319
    br: [],
1320
    col: [],
1321
    code: [],
1322
    div: [],
1323
    em: [],
1324
    hr: [],
1325
    h1: [],
1326
    h2: [],
1327
    h3: [],
1328
    h4: [],
1329
    h5: [],
1330
    h6: [],
1331
    i: [],
1332
    img: ['src', 'alt', 'title', 'width', 'height'],
1333
    li: [],
1334
    ol: [],
1335
    p: [],
1336
    pre: [],
1337
    s: [],
1338
    small: [],
1339
    span: [],
1340
    sub: [],
1341
    sup: [],
1342
    strong: [],
1343
    u: [],
1344
    ul: []
1345
  }
1346
1347
  /**
1348
   * A pattern that recognizes a commonly useful subset of URLs that are safe.
1349
   *
1350
   * Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts
1351
   */
1352
  var SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file):|[^&:/?#]*(?:[/?#]|$))/gi
1353
1354
  /**
1355
   * A pattern that matches safe data URLs. Only matches image, video and audio types.
1356
   *
1357
   * Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts
1358
   */
1359
  var DATA_URL_PATTERN = /^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[a-z0-9+/]+=*$/i
1360
1361
  function allowedAttribute(attr, allowedAttributeList) {
1362
    var attrName = attr.nodeName.toLowerCase()
1363
1364
    if ($.inArray(attrName, allowedAttributeList) !== -1) {
1365
      if ($.inArray(attrName, uriAttrs) !== -1) {
1366
        return Boolean(attr.nodeValue.match(SAFE_URL_PATTERN) || attr.nodeValue.match(DATA_URL_PATTERN))
1367
      }
1368
1369
      return true
1370
    }
1371
1372
    var regExp = $(allowedAttributeList).filter(function (index, value) {
1373
      return value instanceof RegExp
1374
    })
1375
1376
    // Check if a regular expression validates the attribute.
1377
    for (var i = 0, l = regExp.length; i < l; i++) {
1378
      if (attrName.match(regExp[i])) {
1379
        return true
1380
      }
1381
    }
1382
1383
    return false
1384
  }
1385
1386
  function sanitizeHtml(unsafeHtml, whiteList, sanitizeFn) {
1387
    if (unsafeHtml.length === 0) {
1388
      return unsafeHtml
1389
    }
1390
1391
    if (sanitizeFn && typeof sanitizeFn === 'function') {
1392
      return sanitizeFn(unsafeHtml)
1393
    }
1394
1395
    // IE 8 and below don't support createHTMLDocument
1396
    if (!document.implementation || !document.implementation.createHTMLDocument) {
1397
      return unsafeHtml
1398
    }
1399
1400
    var createdDocument = document.implementation.createHTMLDocument('sanitization')
1401
    createdDocument.body.innerHTML = unsafeHtml
1402
1403
    var whitelistKeys = $.map(whiteList, function (el, i) { return i })
1404
    var elements = $(createdDocument.body).find('*')
1405
1406
    for (var i = 0, len = elements.length; i < len; i++) {
1407
      var el = elements[i]
1408
      var elName = el.nodeName.toLowerCase()
1409
1410
      if ($.inArray(elName, whitelistKeys) === -1) {
1411
        el.parentNode.removeChild(el)
1412
1413
        continue
1414
      }
1415
1416
      var attributeList = $.map(el.attributes, function (el) { return el })
1417
      var whitelistedAttributes = [].concat(whiteList['*'] || [], whiteList[elName] || [])
1418
1419
      for (var j = 0, len2 = attributeList.length; j < len2; j++) {
1420
        if (!allowedAttribute(attributeList[j], whitelistedAttributes)) {
1421
          el.removeAttribute(attributeList[j].nodeName)
1422
        }
1423
      }
1424
    }
1425
1426
    return createdDocument.body.innerHTML
1427
  }
1428
1429
  // TOOLTIP PUBLIC CLASS DEFINITION
1430
  // ===============================
1431
1432
  var Tooltip = function (element, options) {
1433
    this.type       = null
1434
    this.options    = null
1435
    this.enabled    = null
1436
    this.timeout    = null
1437
    this.hoverState = null
1438
    this.$element   = null
1439
    this.inState    = null
1440
1441
    this.init('tooltip', element, options)
1442
  }
1443
1444
  Tooltip.VERSION  = '3.4.1'
1445
1446
  Tooltip.TRANSITION_DURATION = 150
1447
1448
  Tooltip.DEFAULTS = {
1449
    animation: true,
1450
    placement: 'top',
1451
    selector: false,
1452
    template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',
1453
    trigger: 'hover focus',
1454
    title: '',
1455
    delay: 0,
1456
    html: false,
1457
    container: false,
1458
    viewport: {
1459
      selector: 'body',
1460
      padding: 0
1461
    },
1462
    sanitize : true,
1463
    sanitizeFn : null,
1464
    whiteList : DefaultWhitelist
1465
  }
1466
1467
  Tooltip.prototype.init = function (type, element, options) {
1468
    this.enabled   = true
1469
    this.type      = type
1470
    this.$element  = $(element)
1471
    this.options   = this.getOptions(options)
1472
    this.$viewport = this.options.viewport && $(document).find($.isFunction(this.options.viewport) ? this.options.viewport.call(this, this.$element) : (this.options.viewport.selector || this.options.viewport))
1473
    this.inState   = { click: false, hover: false, focus: false }
1474
1475
    if (this.$element[0] instanceof document.constructor && !this.options.selector) {
1476
      throw new Error('`selector` option must be specified when initializing ' + this.type + ' on the window.document object!')
1477
    }
1478
1479
    var triggers = this.options.trigger.split(' ')
1480
1481
    for (var i = triggers.length; i--;) {
1482
      var trigger = triggers[i]
1483
1484
      if (trigger == 'click') {
1485
        this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
1486
      } else if (trigger != 'manual') {
1487
        var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin'
1488
        var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
1489
1490
        this.$element.on(eventIn  + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
1491
        this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
1492
      }
1493
    }
1494
1495
    this.options.selector ?
1496
      (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
1497
      this.fixTitle()
1498
  }
1499
1500
  Tooltip.prototype.getDefaults = function () {
1501
    return Tooltip.DEFAULTS
1502
  }
1503
1504
  Tooltip.prototype.getOptions = function (options) {
1505
    var dataAttributes = this.$element.data()
1506
1507
    for (var dataAttr in dataAttributes) {
1508
      if (dataAttributes.hasOwnProperty(dataAttr) && $.inArray(dataAttr, DISALLOWED_ATTRIBUTES) !== -1) {
1509
        delete dataAttributes[dataAttr]
1510
      }
1511
    }
1512
1513
    options = $.extend({}, this.getDefaults(), dataAttributes, options)
1514
1515
    if (options.delay && typeof options.delay == 'number') {
1516
      options.delay = {
1517
        show: options.delay,
1518
        hide: options.delay
1519
      }
1520
    }
1521
1522
    if (options.sanitize) {
1523
      options.template = sanitizeHtml(options.template, options.whiteList, options.sanitizeFn)
1524
    }
1525
1526
    return options
1527
  }
1528
1529
  Tooltip.prototype.getDelegateOptions = function () {
1530
    var options  = {}
1531
    var defaults = this.getDefaults()
1532
1533
    this._options && $.each(this._options, function (key, value) {
1534
      if (defaults[key] != value) options[key] = value
1535
    })
1536
1537
    return options
1538
  }
1539
1540
  Tooltip.prototype.enter = function (obj) {
1541
    var self = obj instanceof this.constructor ?
1542
      obj : $(obj.currentTarget).data('bs.' + this.type)
1543
1544
    if (!self) {
1545
      self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
1546
      $(obj.currentTarget).data('bs.' + this.type, self)
1547
    }
1548
1549
    if (obj instanceof $.Event) {
1550
      self.inState[obj.type == 'focusin' ? 'focus' : 'hover'] = true
1551
    }
1552
1553
    if (self.tip().hasClass('in') || self.hoverState == 'in') {
1554
      self.hoverState = 'in'
1555
      return
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
1556
    }
1557
1558
    clearTimeout(self.timeout)
1559
1560
    self.hoverState = 'in'
1561
1562
    if (!self.options.delay || !self.options.delay.show) return self.show()
1563
1564
    self.timeout = setTimeout(function () {
1565
      if (self.hoverState == 'in') self.show()
1566
    }, self.options.delay.show)
1567
  }
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
1568
1569
  Tooltip.prototype.isInStateTrue = function () {
1570
    for (var key in this.inState) {
0 ignored issues
show
Complexity introduced by
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

When iterating over the keys of an object, this includes not only the keys of the object, but also keys contained in the prototype of that object. It is generally a best practice to check for these keys specifically:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
1571
      if (this.inState[key]) return true
1572
    }
1573
1574
    return false
1575
  }
1576
1577
  Tooltip.prototype.leave = function (obj) {
1578
    var self = obj instanceof this.constructor ?
1579
      obj : $(obj.currentTarget).data('bs.' + this.type)
1580
1581
    if (!self) {
1582
      self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
1583
      $(obj.currentTarget).data('bs.' + this.type, self)
1584
    }
1585
1586
    if (obj instanceof $.Event) {
1587
      self.inState[obj.type == 'focusout' ? 'focus' : 'hover'] = false
1588
    }
1589
1590
    if (self.isInStateTrue()) return
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
1591
1592
    clearTimeout(self.timeout)
1593
1594
    self.hoverState = 'out'
1595
1596
    if (!self.options.delay || !self.options.delay.hide) return self.hide()
1597
1598
    self.timeout = setTimeout(function () {
1599
      if (self.hoverState == 'out') self.hide()
1600
    }, self.options.delay.hide)
1601
  }
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
1602
1603
  Tooltip.prototype.show = function () {
1604
    var e = $.Event('show.bs.' + this.type)
1605
1606
    if (this.hasContent() && this.enabled) {
1607
      this.$element.trigger(e)
1608
1609
      var inDom = $.contains(this.$element[0].ownerDocument.documentElement, this.$element[0])
1610
      if (e.isDefaultPrevented() || !inDom) return
1611
      var that = this
1612
1613
      var $tip = this.tip()
1614
1615
      var tipId = this.getUID(this.type)
1616
1617
      this.setContent()
1618
      $tip.attr('id', tipId)
1619
      this.$element.attr('aria-describedby', tipId)
1620
1621
      if (this.options.animation) $tip.addClass('fade')
1622
1623
      var placement = typeof this.options.placement == 'function' ?
1624
        this.options.placement.call(this, $tip[0], this.$element[0]) :
1625
        this.options.placement
1626
1627
      var autoToken = /\s?auto?\s?/i
1628
      var autoPlace = autoToken.test(placement)
1629
      if (autoPlace) placement = placement.replace(autoToken, '') || 'top'
1630
1631
      $tip
1632
        .detach()
1633
        .css({ top: 0, left: 0, display: 'block' })
1634
        .addClass(placement)
1635
        .data('bs.' + this.type, this)
1636
1637
      this.options.container ? $tip.appendTo($(document).find(this.options.container)) : $tip.insertAfter(this.$element)
1638
      this.$element.trigger('inserted.bs.' + this.type)
1639
1640
      var pos          = this.getPosition()
1641
      var actualWidth  = $tip[0].offsetWidth
1642
      var actualHeight = $tip[0].offsetHeight
1643
1644
      if (autoPlace) {
1645
        var orgPlacement = placement
1646
        var viewportDim = this.getPosition(this.$viewport)
1647
1648
        placement = placement == 'bottom' && pos.bottom + actualHeight > viewportDim.bottom ? 'top'    :
1649
                    placement == 'top'    && pos.top    - actualHeight < viewportDim.top    ? 'bottom' :
1650
                    placement == 'right'  && pos.right  + actualWidth  > viewportDim.width  ? 'left'   :
1651
                    placement == 'left'   && pos.left   - actualWidth  < viewportDim.left   ? 'right'  :
1652
                    placement
1653
1654
        $tip
1655
          .removeClass(orgPlacement)
1656
          .addClass(placement)
1657
      }
1658
1659
      var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
1660
1661
      this.applyPlacement(calculatedOffset, placement)
1662
1663
      var complete = function () {
1664
        var prevHoverState = that.hoverState
1665
        that.$element.trigger('shown.bs.' + that.type)
1666
        that.hoverState = null
1667
1668
        if (prevHoverState == 'out') that.leave(that)
1669
      }
1670
1671
      $.support.transition && this.$tip.hasClass('fade') ?
1672
        $tip
1673
          .one('bsTransitionEnd', complete)
1674
          .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
1675
        complete()
1676
    }
1677
  }
1678
1679
  Tooltip.prototype.applyPlacement = function (offset, placement) {
1680
    var $tip   = this.tip()
1681
    var width  = $tip[0].offsetWidth
1682
    var height = $tip[0].offsetHeight
1683
1684
    // manually read margins because getBoundingClientRect includes difference
1685
    var marginTop = parseInt($tip.css('margin-top'), 10)
1686
    var marginLeft = parseInt($tip.css('margin-left'), 10)
1687
1688
    // we must check for NaN for ie 8/9
1689
    if (isNaN(marginTop))  marginTop  = 0
1690
    if (isNaN(marginLeft)) marginLeft = 0
1691
1692
    offset.top  += marginTop
1693
    offset.left += marginLeft
1694
1695
    // $.fn.offset doesn't round pixel values
1696
    // so we use setOffset directly with our own function B-0
1697
    $.offset.setOffset($tip[0], $.extend({
1698
      using: function (props) {
1699
        $tip.css({
1700
          top: Math.round(props.top),
1701
          left: Math.round(props.left)
1702
        })
1703
      }
1704
    }, offset), 0)
1705
1706
    $tip.addClass('in')
1707
1708
    // check to see if placing tip in new offset caused the tip to resize itself
1709
    var actualWidth  = $tip[0].offsetWidth
1710
    var actualHeight = $tip[0].offsetHeight
1711
1712
    if (placement == 'top' && actualHeight != height) {
1713
      offset.top = offset.top + height - actualHeight
1714
    }
1715
1716
    var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight)
1717
1718
    if (delta.left) offset.left += delta.left
1719
    else offset.top += delta.top
1720
1721
    var isVertical          = /top|bottom/.test(placement)
1722
    var arrowDelta          = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight
1723
    var arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight'
1724
1725
    $tip.offset(offset)
1726
    this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical)
1727
  }
1728
1729
  Tooltip.prototype.replaceArrow = function (delta, dimension, isVertical) {
1730
    this.arrow()
1731
      .css(isVertical ? 'left' : 'top', 50 * (1 - delta / dimension) + '%')
1732
      .css(isVertical ? 'top' : 'left', '')
1733
  }
1734
1735
  Tooltip.prototype.setContent = function () {
1736
    var $tip  = this.tip()
1737
    var title = this.getTitle()
1738
1739
    if (this.options.html) {
1740
      if (this.options.sanitize) {
1741
        title = sanitizeHtml(title, this.options.whiteList, this.options.sanitizeFn)
1742
      }
1743
1744
      $tip.find('.tooltip-inner').html(title)
1745
    } else {
1746
      $tip.find('.tooltip-inner').text(title)
1747
    }
1748
1749
    $tip.removeClass('fade in top bottom left right')
1750
  }
1751
1752
  Tooltip.prototype.hide = function (callback) {
1753
    var that = this
1754
    var $tip = $(this.$tip)
1755
    var e    = $.Event('hide.bs.' + this.type)
1756
1757
    function complete() {
1758
      if (that.hoverState != 'in') $tip.detach()
1759
      if (that.$element) { // TODO: Check whether guarding this code with this `if` is really necessary.
1760
        that.$element
1761
          .removeAttr('aria-describedby')
1762
          .trigger('hidden.bs.' + that.type)
1763
      }
1764
      callback && callback()
1765
    }
1766
1767
    this.$element.trigger(e)
1768
1769
    if (e.isDefaultPrevented()) return
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
1770
1771
    $tip.removeClass('in')
1772
1773
    $.support.transition && $tip.hasClass('fade') ?
1774
      $tip
1775
        .one('bsTransitionEnd', complete)
1776
        .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
1777
      complete()
1778
1779
    this.hoverState = null
1780
1781
    return this
1782
  }
1783
1784
  Tooltip.prototype.fixTitle = function () {
1785
    var $e = this.$element
1786
    if ($e.attr('title') || typeof $e.attr('data-original-title') != 'string') {
1787
      $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
1788
    }
1789
  }
1790
1791
  Tooltip.prototype.hasContent = function () {
1792
    return this.getTitle()
1793
  }
1794
1795
  Tooltip.prototype.getPosition = function ($element) {
1796
    $element   = $element || this.$element
1797
1798
    var el     = $element[0]
1799
    var isBody = el.tagName == 'BODY'
1800
1801
    var elRect    = el.getBoundingClientRect()
1802
    if (elRect.width == null) {
1803
      // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093
1804
      elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top })
1805
    }
1806
    var isSvg = window.SVGElement && el instanceof window.SVGElement
1807
    // Avoid using $.offset() on SVGs since it gives incorrect results in jQuery 3.
1808
    // See https://github.com/twbs/bootstrap/issues/20280
1809
    var elOffset  = isBody ? { top: 0, left: 0 } : (isSvg ? null : $element.offset())
1810
    var scroll    = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() }
1811
    var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null
1812
1813
    return $.extend({}, elRect, scroll, outerDims, elOffset)
1814
  }
1815
1816
  Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
1817
    return placement == 'bottom' ? { top: pos.top + pos.height,   left: pos.left + pos.width / 2 - actualWidth / 2 } :
1818
           placement == 'top'    ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } :
1819
           placement == 'left'   ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
1820
        /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width }
1821
1822
  }
1823
1824
  Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) {
1825
    var delta = { top: 0, left: 0 }
1826
    if (!this.$viewport) return delta
1827
1828
    var viewportPadding = this.options.viewport && this.options.viewport.padding || 0
1829
    var viewportDimensions = this.getPosition(this.$viewport)
1830
1831
    if (/right|left/.test(placement)) {
1832
      var topEdgeOffset    = pos.top - viewportPadding - viewportDimensions.scroll
1833
      var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight
1834
      if (topEdgeOffset < viewportDimensions.top) { // top overflow
1835
        delta.top = viewportDimensions.top - topEdgeOffset
1836
      } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow
1837
        delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset
1838
      }
1839
    } else {
1840
      var leftEdgeOffset  = pos.left - viewportPadding
1841
      var rightEdgeOffset = pos.left + viewportPadding + actualWidth
1842
      if (leftEdgeOffset < viewportDimensions.left) { // left overflow
1843
        delta.left = viewportDimensions.left - leftEdgeOffset
1844
      } else if (rightEdgeOffset > viewportDimensions.right) { // right overflow
1845
        delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset
1846
      }
1847
    }
1848
1849
    return delta
1850
  }
1851
1852
  Tooltip.prototype.getTitle = function () {
1853
    var title
1854
    var $e = this.$element
1855
    var o  = this.options
1856
1857
    title = $e.attr('data-original-title')
1858
      || (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title)
1859
1860
    return title
1861
  }
1862
1863
  Tooltip.prototype.getUID = function (prefix) {
1864
    do prefix += ~~(Math.random() * 1000000)
1865
    while (document.getElementById(prefix))
1866
    return prefix
1867
  }
1868
1869
  Tooltip.prototype.tip = function () {
1870
    if (!this.$tip) {
1871
      this.$tip = $(this.options.template)
1872
      if (this.$tip.length != 1) {
1873
        throw new Error(this.type + ' `template` option must consist of exactly 1 top-level element!')
1874
      }
1875
    }
1876
    return this.$tip
1877
  }
1878
1879
  Tooltip.prototype.arrow = function () {
1880
    return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow'))
1881
  }
1882
1883
  Tooltip.prototype.enable = function () {
1884
    this.enabled = true
1885
  }
1886
1887
  Tooltip.prototype.disable = function () {
1888
    this.enabled = false
1889
  }
1890
1891
  Tooltip.prototype.toggleEnabled = function () {
1892
    this.enabled = !this.enabled
1893
  }
1894
1895
  Tooltip.prototype.toggle = function (e) {
1896
    var self = this
1897
    if (e) {
1898
      self = $(e.currentTarget).data('bs.' + this.type)
1899
      if (!self) {
1900
        self = new this.constructor(e.currentTarget, this.getDelegateOptions())
1901
        $(e.currentTarget).data('bs.' + this.type, self)
1902
      }
1903
    }
1904
1905
    if (e) {
1906
      self.inState.click = !self.inState.click
1907
      if (self.isInStateTrue()) self.enter(self)
1908
      else self.leave(self)
1909
    } else {
1910
      self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
1911
    }
1912
  }
1913
1914
  Tooltip.prototype.destroy = function () {
1915
    var that = this
1916
    clearTimeout(this.timeout)
1917
    this.hide(function () {
1918
      that.$element.off('.' + that.type).removeData('bs.' + that.type)
1919
      if (that.$tip) {
1920
        that.$tip.detach()
1921
      }
1922
      that.$tip = null
1923
      that.$arrow = null
1924
      that.$viewport = null
1925
      that.$element = null
1926
    })
1927
  }
1928
1929
  Tooltip.prototype.sanitizeHtml = function (unsafeHtml) {
1930
    return sanitizeHtml(unsafeHtml, this.options.whiteList, this.options.sanitizeFn)
1931
  }
1932
1933
  // TOOLTIP PLUGIN DEFINITION
1934
  // =========================
1935
1936
  function Plugin(option) {
1937
    return this.each(function () {
1938
      var $this   = $(this)
1939
      var data    = $this.data('bs.tooltip')
1940
      var options = typeof option == 'object' && option
1941
1942
      if (!data && /destroy|hide/.test(option)) return
1943
      if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
1944
      if (typeof option == 'string') data[option]()
1945
    })
1946
  }
1947
1948
  var old = $.fn.tooltip
1949
1950
  $.fn.tooltip             = Plugin
1951
  $.fn.tooltip.Constructor = Tooltip
1952
1953
1954
  // TOOLTIP NO CONFLICT
1955
  // ===================
1956
1957
  $.fn.tooltip.noConflict = function () {
1958
    $.fn.tooltip = old
1959
    return this
1960
  }
1961
1962
}(jQuery);
1963
1964
/* ========================================================================
1965
 * Bootstrap: popover.js v3.4.1
1966
 * https://getbootstrap.com/docs/3.4/javascript/#popovers
1967
 * ========================================================================
1968
 * Copyright 2011-2019 Twitter, Inc.
1969
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
1970
 * ======================================================================== */
1971
1972
1973
+function ($) {
1974
  'use strict';
1975
1976
  // POPOVER PUBLIC CLASS DEFINITION
1977
  // ===============================
1978
1979
  var Popover = function (element, options) {
1980
    this.init('popover', element, options)
1981
  }
1982
1983
  if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')
1984
1985
  Popover.VERSION  = '3.4.1'
1986
1987
  Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {
1988
    placement: 'right',
1989
    trigger: 'click',
1990
    content: '',
1991
    template: '<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
1992
  })
1993
1994
1995
  // NOTE: POPOVER EXTENDS tooltip.js
1996
  // ================================
1997
1998
  Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype)
1999
2000
  Popover.prototype.constructor = Popover
2001
2002
  Popover.prototype.getDefaults = function () {
2003
    return Popover.DEFAULTS
2004
  }
2005
2006
  Popover.prototype.setContent = function () {
2007
    var $tip    = this.tip()
2008
    var title   = this.getTitle()
2009
    var content = this.getContent()
2010
2011
    if (this.options.html) {
2012
      var typeContent = typeof content
2013
2014
      if (this.options.sanitize) {
2015
        title = this.sanitizeHtml(title)
2016
2017
        if (typeContent === 'string') {
2018
          content = this.sanitizeHtml(content)
2019
        }
2020
      }
2021
2022
      $tip.find('.popover-title').html(title)
2023
      $tip.find('.popover-content').children().detach().end()[
2024
        typeContent === 'string' ? 'html' : 'append'
2025
      ](content)
2026
    } else {
2027
      $tip.find('.popover-title').text(title)
2028
      $tip.find('.popover-content').children().detach().end().text(content)
2029
    }
2030
2031
    $tip.removeClass('fade top bottom left right in')
2032
2033
    // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
2034
    // this manually by checking the contents.
2035
    if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide()
2036
  }
2037
2038
  Popover.prototype.hasContent = function () {
2039
    return this.getTitle() || this.getContent()
2040
  }
2041
2042
  Popover.prototype.getContent = function () {
2043
    var $e = this.$element
2044
    var o  = this.options
2045
2046
    return $e.attr('data-content')
2047
      || (typeof o.content == 'function' ?
2048
        o.content.call($e[0]) :
2049
        o.content)
2050
  }
2051
2052
  Popover.prototype.arrow = function () {
2053
    return (this.$arrow = this.$arrow || this.tip().find('.arrow'))
2054
  }
2055
2056
2057
  // POPOVER PLUGIN DEFINITION
2058
  // =========================
2059
2060
  function Plugin(option) {
2061
    return this.each(function () {
2062
      var $this   = $(this)
2063
      var data    = $this.data('bs.popover')
2064
      var options = typeof option == 'object' && option
2065
2066
      if (!data && /destroy|hide/.test(option)) return
2067
      if (!data) $this.data('bs.popover', (data = new Popover(this, options)))
2068
      if (typeof option == 'string') data[option]()
2069
    })
2070
  }
2071
2072
  var old = $.fn.popover
2073
2074
  $.fn.popover             = Plugin
2075
  $.fn.popover.Constructor = Popover
2076
2077
2078
  // POPOVER NO CONFLICT
2079
  // ===================
2080
2081
  $.fn.popover.noConflict = function () {
2082
    $.fn.popover = old
2083
    return this
2084
  }
2085
2086
}(jQuery);
2087
2088
/* ========================================================================
2089
 * Bootstrap: scrollspy.js v3.4.1
2090
 * https://getbootstrap.com/docs/3.4/javascript/#scrollspy
2091
 * ========================================================================
2092
 * Copyright 2011-2019 Twitter, Inc.
2093
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
2094
 * ======================================================================== */
2095
2096
2097
+function ($) {
2098
  'use strict';
2099
2100
  // SCROLLSPY CLASS DEFINITION
2101
  // ==========================
2102
2103
  function ScrollSpy(element, options) {
2104
    this.$body          = $(document.body)
2105
    this.$scrollElement = $(element).is(document.body) ? $(window) : $(element)
2106
    this.options        = $.extend({}, ScrollSpy.DEFAULTS, options)
2107
    this.selector       = (this.options.target || '') + ' .nav li > a'
2108
    this.offsets        = []
2109
    this.targets        = []
2110
    this.activeTarget   = null
2111
    this.scrollHeight   = 0
2112
2113
    this.$scrollElement.on('scroll.bs.scrollspy', $.proxy(this.process, this))
2114
    this.refresh()
2115
    this.process()
2116
  }
2117
2118
  ScrollSpy.VERSION  = '3.4.1'
2119
2120
  ScrollSpy.DEFAULTS = {
2121
    offset: 10
2122
  }
2123
2124
  ScrollSpy.prototype.getScrollHeight = function () {
2125
    return this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight)
2126
  }
2127
2128
  ScrollSpy.prototype.refresh = function () {
2129
    var that          = this
2130
    var offsetMethod  = 'offset'
2131
    var offsetBase    = 0
2132
2133
    this.offsets      = []
2134
    this.targets      = []
2135
    this.scrollHeight = this.getScrollHeight()
2136
2137
    if (!$.isWindow(this.$scrollElement[0])) {
2138
      offsetMethod = 'position'
2139
      offsetBase   = this.$scrollElement.scrollTop()
2140
    }
2141
2142
    this.$body
2143
      .find(this.selector)
2144
      .map(function () {
2145
        var $el   = $(this)
2146
        var href  = $el.data('target') || $el.attr('href')
2147
        var $href = /^#./.test(href) && $(href)
2148
2149
        return ($href
2150
          && $href.length
2151
          && $href.is(':visible')
2152
          && [[$href[offsetMethod]().top + offsetBase, href]]) || null
2153
      })
2154
      .sort(function (a, b) { return a[0] - b[0] })
2155
      .each(function () {
2156
        that.offsets.push(this[0])
2157
        that.targets.push(this[1])
2158
      })
2159
  }
2160
2161
  ScrollSpy.prototype.process = function () {
2162
    var scrollTop    = this.$scrollElement.scrollTop() + this.options.offset
2163
    var scrollHeight = this.getScrollHeight()
2164
    var maxScroll    = this.options.offset + scrollHeight - this.$scrollElement.height()
2165
    var offsets      = this.offsets
2166
    var targets      = this.targets
2167
    var activeTarget = this.activeTarget
2168
    var i
2169
2170
    if (this.scrollHeight != scrollHeight) {
2171
      this.refresh()
2172
    }
2173
2174
    if (scrollTop >= maxScroll) {
2175
      return activeTarget != (i = targets[targets.length - 1]) && this.activate(i)
2176
    }
2177
2178
    if (activeTarget && scrollTop < offsets[0]) {
2179
      this.activeTarget = null
2180
      return this.clear()
2181
    }
2182
2183
    for (i = offsets.length; i--;) {
2184
      activeTarget != targets[i]
2185
        && scrollTop >= offsets[i]
2186
        && (offsets[i + 1] === undefined || scrollTop < offsets[i + 1])
2187
        && this.activate(targets[i])
2188
    }
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
2189
  }
2190
2191
  ScrollSpy.prototype.activate = function (target) {
2192
    this.activeTarget = target
2193
2194
    this.clear()
2195
2196
    var selector = this.selector +
2197
      '[data-target="' + target + '"],' +
2198
      this.selector + '[href="' + target + '"]'
2199
2200
    var active = $(selector)
2201
      .parents('li')
2202
      .addClass('active')
2203
2204
    if (active.parent('.dropdown-menu').length) {
2205
      active = active
2206
        .closest('li.dropdown')
2207
        .addClass('active')
2208
    }
2209
2210
    active.trigger('activate.bs.scrollspy')
2211
  }
2212
2213
  ScrollSpy.prototype.clear = function () {
2214
    $(this.selector)
2215
      .parentsUntil(this.options.target, '.active')
2216
      .removeClass('active')
2217
  }
2218
2219
2220
  // SCROLLSPY PLUGIN DEFINITION
2221
  // ===========================
2222
2223
  function Plugin(option) {
2224
    return this.each(function () {
2225
      var $this   = $(this)
2226
      var data    = $this.data('bs.scrollspy')
2227
      var options = typeof option == 'object' && option
2228
2229
      if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options)))
2230
      if (typeof option == 'string') data[option]()
2231
    })
2232
  }
2233
2234
  var old = $.fn.scrollspy
2235
2236
  $.fn.scrollspy             = Plugin
2237
  $.fn.scrollspy.Constructor = ScrollSpy
2238
2239
2240
  // SCROLLSPY NO CONFLICT
2241
  // =====================
2242
2243
  $.fn.scrollspy.noConflict = function () {
2244
    $.fn.scrollspy = old
2245
    return this
2246
  }
2247
2248
2249
  // SCROLLSPY DATA-API
2250
  // ==================
2251
2252
  $(window).on('load.bs.scrollspy.data-api', function () {
2253
    $('[data-spy="scroll"]').each(function () {
2254
      var $spy = $(this)
2255
      Plugin.call($spy, $spy.data())
2256
    })
2257
  })
2258
2259
}(jQuery);
2260
2261
/* ========================================================================
2262
 * Bootstrap: tab.js v3.4.1
2263
 * https://getbootstrap.com/docs/3.4/javascript/#tabs
2264
 * ========================================================================
2265
 * Copyright 2011-2019 Twitter, Inc.
2266
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
2267
 * ======================================================================== */
2268
2269
2270
+function ($) {
2271
  'use strict';
2272
2273
  // TAB CLASS DEFINITION
2274
  // ====================
2275
2276
  var Tab = function (element) {
2277
    // jscs:disable requireDollarBeforejQueryAssignment
2278
    this.element = $(element)
2279
    // jscs:enable requireDollarBeforejQueryAssignment
2280
  }
2281
2282
  Tab.VERSION = '3.4.1'
2283
2284
  Tab.TRANSITION_DURATION = 150
2285
2286
  Tab.prototype.show = function () {
2287
    var $this    = this.element
2288
    var $ul      = $this.closest('ul:not(.dropdown-menu)')
2289
    var selector = $this.data('target')
2290
2291
    if (!selector) {
2292
      selector = $this.attr('href')
2293
      selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
2294
    }
2295
2296
    if ($this.parent('li').hasClass('active')) return
2297
2298
    var $previous = $ul.find('.active:last a')
2299
    var hideEvent = $.Event('hide.bs.tab', {
2300
      relatedTarget: $this[0]
2301
    })
2302
    var showEvent = $.Event('show.bs.tab', {
2303
      relatedTarget: $previous[0]
2304
    })
2305
2306
    $previous.trigger(hideEvent)
2307
    $this.trigger(showEvent)
2308
2309
    if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) return
2310
2311
    var $target = $(document).find(selector)
2312
2313
    this.activate($this.closest('li'), $ul)
2314
    this.activate($target, $target.parent(), function () {
2315
      $previous.trigger({
2316
        type: 'hidden.bs.tab',
2317
        relatedTarget: $this[0]
2318
      })
2319
      $this.trigger({
2320
        type: 'shown.bs.tab',
2321
        relatedTarget: $previous[0]
2322
      })
2323
    })
2324
  }
2325
2326
  Tab.prototype.activate = function (element, container, callback) {
2327
    var $active    = container.find('> .active')
2328
    var transition = callback
2329
      && $.support.transition
2330
      && ($active.length && $active.hasClass('fade') || !!container.find('> .fade').length)
2331
2332
    function next() {
2333
      $active
2334
        .removeClass('active')
2335
        .find('> .dropdown-menu > .active')
2336
        .removeClass('active')
2337
        .end()
2338
        .find('[data-toggle="tab"]')
2339
        .attr('aria-expanded', false)
2340
2341
      element
2342
        .addClass('active')
2343
        .find('[data-toggle="tab"]')
2344
        .attr('aria-expanded', true)
2345
2346
      if (transition) {
2347
        element[0].offsetWidth // reflow for transition
0 ignored issues
show
introduced by
The result of the property access to element.0.offsetWidth is not used.
Loading history...
2348
        element.addClass('in')
2349
      } else {
2350
        element.removeClass('fade')
2351
      }
2352
2353
      if (element.parent('.dropdown-menu').length) {
2354
        element
2355
          .closest('li.dropdown')
2356
          .addClass('active')
2357
          .end()
2358
          .find('[data-toggle="tab"]')
2359
          .attr('aria-expanded', true)
2360
      }
2361
2362
      callback && callback()
2363
    }
2364
2365
    $active.length && transition ?
2366
      $active
2367
        .one('bsTransitionEnd', next)
2368
        .emulateTransitionEnd(Tab.TRANSITION_DURATION) :
2369
      next()
2370
2371
    $active.removeClass('in')
2372
  }
2373
2374
2375
  // TAB PLUGIN DEFINITION
2376
  // =====================
2377
2378
  function Plugin(option) {
2379
    return this.each(function () {
2380
      var $this = $(this)
2381
      var data  = $this.data('bs.tab')
2382
2383
      if (!data) $this.data('bs.tab', (data = new Tab(this)))
2384
      if (typeof option == 'string') data[option]()
2385
    })
2386
  }
2387
2388
  var old = $.fn.tab
2389
2390
  $.fn.tab             = Plugin
2391
  $.fn.tab.Constructor = Tab
2392
2393
2394
  // TAB NO CONFLICT
2395
  // ===============
2396
2397
  $.fn.tab.noConflict = function () {
2398
    $.fn.tab = old
2399
    return this
2400
  }
2401
2402
2403
  // TAB DATA-API
2404
  // ============
2405
2406
  var clickHandler = function (e) {
2407
    e.preventDefault()
2408
    Plugin.call($(this), 'show')
2409
  }
2410
2411
  $(document)
2412
    .on('click.bs.tab.data-api', '[data-toggle="tab"]', clickHandler)
2413
    .on('click.bs.tab.data-api', '[data-toggle="pill"]', clickHandler)
2414
2415
}(jQuery);
2416
2417
/* ========================================================================
2418
 * Bootstrap: affix.js v3.4.1
2419
 * https://getbootstrap.com/docs/3.4/javascript/#affix
2420
 * ========================================================================
2421
 * Copyright 2011-2019 Twitter, Inc.
2422
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
2423
 * ======================================================================== */
2424
2425
2426
+function ($) {
2427
  'use strict';
2428
2429
  // AFFIX CLASS DEFINITION
2430
  // ======================
2431
2432
  var Affix = function (element, options) {
2433
    this.options = $.extend({}, Affix.DEFAULTS, options)
2434
2435
    var target = this.options.target === Affix.DEFAULTS.target ? $(this.options.target) : $(document).find(this.options.target)
2436
2437
    this.$target = target
2438
      .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this))
2439
      .on('click.bs.affix.data-api',  $.proxy(this.checkPositionWithEventLoop, this))
2440
2441
    this.$element     = $(element)
2442
    this.affixed      = null
2443
    this.unpin        = null
2444
    this.pinnedOffset = null
2445
2446
    this.checkPosition()
2447
  }
2448
2449
  Affix.VERSION  = '3.4.1'
2450
2451
  Affix.RESET    = 'affix affix-top affix-bottom'
2452
2453
  Affix.DEFAULTS = {
2454
    offset: 0,
2455
    target: window
2456
  }
2457
2458
  Affix.prototype.getState = function (scrollHeight, height, offsetTop, offsetBottom) {
2459
    var scrollTop    = this.$target.scrollTop()
2460
    var position     = this.$element.offset()
2461
    var targetHeight = this.$target.height()
2462
2463
    if (offsetTop != null && this.affixed == 'top') return scrollTop < offsetTop ? 'top' : false
2464
2465
    if (this.affixed == 'bottom') {
2466
      if (offsetTop != null) return (scrollTop + this.unpin <= position.top) ? false : 'bottom'
2467
      return (scrollTop + targetHeight <= scrollHeight - offsetBottom) ? false : 'bottom'
2468
    }
2469
2470
    var initializing   = this.affixed == null
2471
    var colliderTop    = initializing ? scrollTop : position.top
2472
    var colliderHeight = initializing ? targetHeight : height
2473
2474
    if (offsetTop != null && scrollTop <= offsetTop) return 'top'
2475
    if (offsetBottom != null && (colliderTop + colliderHeight >= scrollHeight - offsetBottom)) return 'bottom'
2476
2477
    return false
2478
  }
2479
2480
  Affix.prototype.getPinnedOffset = function () {
2481
    if (this.pinnedOffset) return this.pinnedOffset
2482
    this.$element.removeClass(Affix.RESET).addClass('affix')
2483
    var scrollTop = this.$target.scrollTop()
2484
    var position  = this.$element.offset()
2485
    return (this.pinnedOffset = position.top - scrollTop)
2486
  }
2487
2488
  Affix.prototype.checkPositionWithEventLoop = function () {
2489
    setTimeout($.proxy(this.checkPosition, this), 1)
2490
  }
2491
2492
  Affix.prototype.checkPosition = function () {
2493
    if (!this.$element.is(':visible')) return
2494
2495
    var height       = this.$element.height()
2496
    var offset       = this.options.offset
2497
    var offsetTop    = offset.top
2498
    var offsetBottom = offset.bottom
2499
    var scrollHeight = Math.max($(document).height(), $(document.body).height())
2500
2501
    if (typeof offset != 'object')         offsetBottom = offsetTop = offset
2502
    if (typeof offsetTop == 'function')    offsetTop    = offset.top(this.$element)
2503
    if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element)
2504
2505
    var affix = this.getState(scrollHeight, height, offsetTop, offsetBottom)
2506
2507
    if (this.affixed != affix) {
2508
      if (this.unpin != null) this.$element.css('top', '')
2509
2510
      var affixType = 'affix' + (affix ? '-' + affix : '')
2511
      var e         = $.Event(affixType + '.bs.affix')
2512
2513
      this.$element.trigger(e)
2514
2515
      if (e.isDefaultPrevented()) return
2516
2517
      this.affixed = affix
2518
      this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null
2519
2520
      this.$element
2521
        .removeClass(Affix.RESET)
2522
        .addClass(affixType)
2523
        .trigger(affixType.replace('affix', 'affixed') + '.bs.affix')
2524
    }
2525
2526
    if (affix == 'bottom') {
2527
      this.$element.offset({
2528
        top: scrollHeight - height - offsetBottom
2529
      })
2530
    }
2531
  }
2532
2533
2534
  // AFFIX PLUGIN DEFINITION
2535
  // =======================
2536
2537
  function Plugin(option) {
2538
    return this.each(function () {
2539
      var $this   = $(this)
2540
      var data    = $this.data('bs.affix')
2541
      var options = typeof option == 'object' && option
2542
2543
      if (!data) $this.data('bs.affix', (data = new Affix(this, options)))
2544
      if (typeof option == 'string') data[option]()
2545
    })
2546
  }
2547
2548
  var old = $.fn.affix
2549
2550
  $.fn.affix             = Plugin
2551
  $.fn.affix.Constructor = Affix
2552
2553
2554
  // AFFIX NO CONFLICT
2555
  // =================
2556
2557
  $.fn.affix.noConflict = function () {
2558
    $.fn.affix = old
2559
    return this
2560
  }
2561
2562
2563
  // AFFIX DATA-API
2564
  // ==============
2565
2566
  $(window).on('load', function () {
2567
    $('[data-spy="affix"]').each(function () {
2568
      var $spy = $(this)
2569
      var data = $spy.data()
2570
2571
      data.offset = data.offset || {}
2572
2573
      if (data.offsetBottom != null) data.offset.bottom = data.offsetBottom
2574
      if (data.offsetTop    != null) data.offset.top    = data.offsetTop
2575
2576
      Plugin.call($spy, data)
2577
    })
2578
  })
2579
2580
}(jQuery);
2581